#pragma once

#include <string>
#include <fcntl.h>      // 文件控制定义（如O_RDWR）
#include <unistd.h>     // POSIX标准函数（如read/write）
#include <termios.h>    // 终端I/O控制定义
#include <cerrno>       // 错误号定义
#include <cstring>      // memset等操作
#include <system_error> // 系统错误异常

/**
 * @brief UART通信类V3，基于Linux原生API实现
 * 适用于RK3588 Linux平台，无第三方依赖
 */
class uart_v3 {
private:
    std::string _port_name;     // 串口设备路径（如"/dev/ttyS2"）
    int _fd = -1;               // 文件描述符，初始为无效值
    int _baud_rate;             // 波特率（如115200）
    int _data_bits;             // 数据位（5/6/7/8）
    int _stop_bits;             // 停止位（1/2）
    bool _parity_enabled;       // 是否启用校验位
    bool _odd_parity;           // 是否为奇校验（否则为偶校验）

public:
    /**
     * @brief 构造函数（不自动打开端口）
     * @param port_name 串口设备路径（如"/dev/ttyS2"）
     * @param baud_rate 波特率（支持标准值如115200）
     * @param data_bits 数据位（5/6/7/8）
     * @param stop_bits 停止位（1/2）
     * @param parity 校验方式（0:无校验，1:奇校验，2:偶校验）
     */
    uart_v3(std::string port_name, int baud_rate, int data_bits, 
            int stop_bits, int parity)
        : _port_name(std::move(port_name)),
          _baud_rate(baud_rate),
          _data_bits(data_bits),
          _stop_bits(stop_bits),
          _parity_enabled(parity != 0),
          _odd_parity(parity == 1) {}

    ~uart_v3() {
        if (_fd != -1) close(); // 确保关闭端口
    }

    /**
     * @brief 打开并配置串口
     * @throw std::system_error 操作失败时抛出异常
     */
    void open() {
        // 打开设备（非阻塞模式打开，避免卡住）
        _fd = ::open(_port_name.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
        if (_fd == -1) {
            throw std::system_error(errno, std::system_category(), 
                                  "Open port failed");
        }

        // 获取当前串口配置
        termios tty{};
        if (tcgetattr(_fd, &tty) != 0) {
            ::close(_fd);
            _fd = -1;
            throw std::system_error(errno, std::system_category(), 
                                  "tcgetattr failed");
        }

        /*---------------- 基础配置 ----------------*/
        // 设置为原始模式（禁用标准输入处理）
        cfmakeraw(&tty);
        
        // 输入模式标志
        tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 关闭流控制
        tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);

        // 输出模式标志
        tty.c_oflag &= ~OPOST; // 禁用输出处理

        // 控制模式标志
        tty.c_cflag |= CLOCAL | CREAD; // 忽略调制解调器控制线，启用接收

        /*---------------- 参数配置 ----------------*/
        // 设置波特率
        speed_t speed = B115200; // 默认值
        switch (_baud_rate) {    // 支持常用波特率
            case 9600:   speed = B9600;   break;
            case 19200:  speed = B19200;  break;
            case 38400:  speed = B38400;  break;
            case 115200: speed = B115200; break;
            default: throw std::invalid_argument("Unsupported baud rate");
        }
        cfsetispeed(&tty, speed);
        cfsetospeed(&tty, speed);

        // 数据位
        tty.c_cflag &= ~CSIZE;
        switch (_data_bits) {
            case 5: tty.c_cflag |= CS5; break;
            case 6: tty.c_cflag |= CS6; break;
            case 7: tty.c_cflag |= CS7; break;
            case 8: tty.c_cflag |= CS8; break;
            default: throw std::invalid_argument("Invalid data bits");
        }

        // 停止位
        if (_stop_bits == 1) tty.c_cflag &= ~CSTOPB;
        else if (_stop_bits == 2) tty.c_cflag |= CSTOPB;
        else throw std::invalid_argument("Invalid stop bits");

        // 校验位
        if (_parity_enabled) {
            tty.c_cflag |= PARENB;
            tty.c_cflag |= (_odd_parity ? PARODD : 0);
        } else {
            tty.c_cflag &= ~PARENB;
        }

        // 应用配置
        if (tcsetattr(_fd, TCSANOW, &tty) != 0) {
            ::close(_fd);
            _fd = -1;
            throw std::system_error(errno, std::system_category(), 
                                  "tcsetattr failed");
        }

        // 设置为阻塞模式（可根据需要调整）
        int flags = fcntl(_fd, F_GETFL);
        fcntl(_fd, F_SETFL, flags & ~O_NONBLOCK);
    }

    /**
     * @brief 关闭串口
     */
    void close() {
        if (_fd != -1) {
            ::close(_fd);
            _fd = -1;
        }
    }

    /**
     * @brief 发送数据
     * @param data 待发送数据指针
     * @param len 数据长度
     * @return 实际发送的字节数，负数表示错误
     */
    int send(const uint8_t* data, size_t len) {
        ssize_t sent = ::write(_fd, data, len);
        if (sent < 0) {
            if (errno == EAGAIN) return 0; // 非阻塞模式下可重试
            return -errno; // 返回错误号负值
        }
        return static_cast<int>(sent);
    }

    /**
     * @brief 接收数据
     * @param buffer 接收缓冲区
     * @param max_len 缓冲区最大容量
     * @param timeout_ms 超时时间（毫秒）
     * @return 实际接收的字节数，负数表示错误
     */
    int receive(uint8_t* buffer, size_t max_len, int timeout_ms = 1000) {
        fd_set set;
        struct timeval timeout;

        FD_ZERO(&set);
        FD_SET(_fd, &set);

        timeout.tv_sec = timeout_ms / 1000;
        timeout.tv_usec = (timeout_ms % 1000) * 1000;

        // 使用select等待数据到达
        int ret = select(_fd + 1, &set, nullptr, nullptr, &timeout);
        if (ret < 0) return -errno;   // select错误
        if (ret == 0) return 0;        // 超时

        ssize_t n = ::read(_fd, buffer, max_len);
        if (n < 0) return -errno;      // read错误
        return static_cast<int>(n);    // 返回实际读取字节数
    }

    // 其他辅助方法（可根据需要扩展）
    [[nodiscard]] bool is_open() const { return _fd != -1; }
    [[nodiscard]] std::string port_name() const { return _port_name; }
};